package com.zjdiepu.www.common.util;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
/**
 * 数字运算/格式工具
 * @author xiongxiaotun@126.com
 * @time 2017年3月5日 下午8:51:19
 * @since 1.0.0
 * @update
 */
public class NumberUtil {
	/**
	 * 一位整数一位小数
	 */
	public static final AtomicReference<DecimalFormat> ONE_INTEGER_WITH_ONE_DECIMAL  = new AtomicReference<>(new DecimalFormat("0.0"));
	/**
	 * 一位整数两位小数
	 */
	public static final AtomicReference<DecimalFormat> ONE_INTEGER_WITH_TWO_DECIMAL  = new AtomicReference<>(new DecimalFormat("0.00"));
	/**
	 * 一位整数三位小数
	 */
	public static final AtomicReference<DecimalFormat> ONE_INTEGER_WITH_TREE_DECIMAL  = new AtomicReference<>(new DecimalFormat("0.000"));
	/**
	 * 浮点数精度控制：四舍五入
	 * @author xiongxiaotun <br/>
	 * @Title getBigDecimalHalfUp  <br/>
	 * @Description 浮点数精度控制  <br/>
	 * @param d
	 * @param f
	 * @param scale 数据精度
	 * @return
	 * @version V1.0  <br/>
	 */
	public static double getBigDecimalHalfUp(double d, int f, int scale) {
		BigDecimal bg = new BigDecimal(d).setScale(scale < 0 ? 8 : scale, BigDecimal.ROUND_HALF_UP);
		return bg.setScale(f, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	/**
	 * 浮点数精度控制：只进不舍
	 * @author xiongxiaotun <br/>
	 * @Title getBigDecimalUp  <br/>
	 * @Description 浮点数精度控制  <br/>
	 * @param d
	 * @param f
	 * @param scale 数据精度
	 * @return
	 * @version V1.0  <br/>
	 */
	public static double getBigDecimalUp(double d,int f, int scale) {
		BigDecimal bg = new BigDecimal(d).setScale(scale < 0 ? 8 : scale, BigDecimal.ROUND_HALF_UP);
		return bg.setScale(f, BigDecimal.ROUND_UP).doubleValue();
	}
	/**
	 * 浮点数精度控制：只舍不入
	 * @author xiongxiaotun <br/>
	 * @Title getBigDecimalDown  <br/>
	 * @Description 浮点数精度控制  <br/>
	 * @param d
	 * @param f
	 * @param scale 数据精度
	 * @return
	 * @version V1.0  <br/>
	 */
	public static double getBigDecimalDown(double d, int f, int scale) {
		BigDecimal bg = new BigDecimal(d).setScale(scale < 0 ? 8 : scale, BigDecimal.ROUND_HALF_UP);
		return bg.setScale(f, BigDecimal.ROUND_DOWN).doubleValue();
	}
	
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title isNumber <br/>
	 * @Description 判断是否为数字字符串 <br/>
	 * @param source
	 * @version V1.0  <br/>
	 */
	public static boolean isNumber(String source){
		Pattern pattern = Pattern.compile("^(-?\\d+)(\\.\\d+)?$"); 
	    return pattern.matcher(source).matches();    
	}
	
	/**
	 * 数字格式化<br/>
	 * 至少一位整数;四舍五入<br/>
	 * @author xiongxiaotun@126.com
	 * @time 2017年3月5日 下午9:07:33
	 * @since 1.0.0
	 * @update
	 * @param value 值
	 * @param scale 小数位数
	 * @return
	 */
	public static String format(Number value, int scale) {
		String toFormatStr = null;
		if(null != value) {
			toFormatStr = value.toString();
		}
		return format(toFormatStr, scale);
	}
	
	/**
	 * 数字字符串格式化<br/>
	 * 至少一位整数;四舍五入<br/>
	 * @author xiongxiaotun@126.com
	 * @time 2017年3月5日 下午9:07:33
	 * @since 1.0.0
	 * @update
	 * @param value 值
	 * @param scale 小数位数
	 * @return
	 */
	public static String format(String value, int scale) {
		String formatPattern = (NumberUtils.INTEGER_ZERO.equals(scale) ? StringUtil.STRING_ZERO : 
			(StringUtil.STRING_ZERO + StringUtil.PERIOD)) + StringUtil.createNCharStr(scale, StringUtil.STRING_ZERO);
		DecimalFormat formatter = new DecimalFormat(formatPattern);
		if(StringUtils.isBlank(value)) {
			return formatter.format(NumberUtils.DOUBLE_ZERO);
		}
		BigDecimal bigDecimal = NumberUtils.createBigDecimal(value);
		return formatter.format(bigDecimal);
	}
	
	/**
	 * 浮点数取整数<br/>
	 * 四舍五入<br/>
	 * @author xiongxiaotun@126.com
	 * @time 2017年3月5日 下午9:09:55
	 * @since 1.0.0
	 * @update
	 * @param value
	 * @return
	 */
	public static int covertToInt(Number value) {
		if(null == value) {
			return NumberUtils.INTEGER_ZERO;
		}
		return covertToInt(value.toString());
	}
	
	/**
	 * 数字字符串取整数<br/>
	 * 四舍五入<br/>
	 * @author xiongxiaotun@126.com
	 * @time 2017年3月5日 下午9:29:25
	 * @since 1.0.0
	 * @update
	 * @param value
	 * @return
	 */
	public static int covertToInt(String value) {
		if(null == value) {
			return NumberUtils.INTEGER_ZERO;
		}
		BigDecimal bigDecimal = NumberUtils.createBigDecimal(value);
		return bigDecimal.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
	}
	
	/**
	 * 删除数字尾部多余的零
	 * @author xiongxiaotun@126.com
	 * @time 2017年3月7日 上午7:24:58
	 * @since 1.0.0
	 * @update
	 * @param value
	 * @return
	 */
	public static String trimZeroSuffix(String value) {
		if(StringUtils.isBlank(value)) {
			return StringUtils.EMPTY;
		}
		value = value.trim();
		if (value.indexOf(StringUtil.PERIOD) == -1) {
			return value;
		}
		return value.replaceAll("(0*||\\.0*)$", "");
	}

	/**
	 * 二进制权限模型 需要注意 right 必须是只有一位权限 right 00001 match 11001 return true right
	 * 00001 match 11000 return false
	 * 
	 * @param right
	 *            匹配权限 000001
	 * @param matches
	 *            被匹配权限 111000
	 * @return
	 * 
	 */
	public static boolean hasRight(String right, String matches) {
		int r = Integer.valueOf(right, 2);
		int m = Integer.valueOf(matches, 2);
		return (r & m) != 0;
	}

	private static final Pattern pattern = Pattern.compile("[^\\d]?([\\d]*).*");

	public static String getFirstNumberInStr(String src) {
		Matcher match = pattern.matcher(src);
		if (match.matches()) {
			return match.group(1);
		}
		return null;
	}
	
	
	public static Integer compareDouble(Double paramValue1, Double paramValue2) {
		Double compareValue1 = null != paramValue1 ? paramValue1 : 0;
		Double compareValue2 = null != paramValue2 ? paramValue2 : 0;
		
		BigDecimal decimal1 = new BigDecimal(compareValue1);  
		BigDecimal decimal2 = new BigDecimal(compareValue2); 
		return decimal1.compareTo(decimal2);
	}
	
	public static Integer compareBigDecimal(BigDecimal paramValue1, BigDecimal paramValue2) {
		BigDecimal decimal1 = null != paramValue1 ? paramValue1 : BigDecimal.ZERO;
		BigDecimal decimal2 = null != paramValue2 ? paramValue2 : BigDecimal.ZERO;
		
		return decimal1.compareTo(decimal2);
	}

	/**
	 * Double两值相减
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static Double subDouble(Double paramValue1, Double paramValue2) {
		Double compareValue1 = null != paramValue1 ? paramValue1 : 0;
		Double compareValue2 = null != paramValue2 ? paramValue2 : 0;
		
        BigDecimal decimal1 = new BigDecimal(compareValue1);
        BigDecimal decimal2 = new BigDecimal(compareValue2);
        return decimal1.subtract(decimal2).doubleValue();
	}
	
	/**
	 * Double两值相加
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static Double addDouble(Double paramValue1, Double paramValue2) {
		Double compareValue1 = null != paramValue1 ? paramValue1 : 0;
		Double compareValue2 = null != paramValue2 ? paramValue2 : 0;
		
        BigDecimal decimal1 = new BigDecimal(compareValue1);
        BigDecimal decimal2 = new BigDecimal(compareValue2);
        return decimal1.add(decimal2).doubleValue();
	}
	
	/**
	 * Double两值相加
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static Double addDouble(Double paramValue1, BigDecimal paramValue2) {
		Double compareValue1 = null != paramValue1 ? paramValue1 : 0;
		BigDecimal decimal2 = null != paramValue2 ? paramValue2 : BigDecimal.ZERO;
		
        BigDecimal decimal1 = new BigDecimal(compareValue1);
        return decimal1.add(decimal2).doubleValue();
	}
	
	/**
	 * Double两值相乘
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static Double multiplyDouble(Double paramValue1, Double paramValue2) {
		Double compareValue1 = null != paramValue1 ? paramValue1 : 0;
		Double compareValue2 = null != paramValue2 ? paramValue2 : 0;
		
        BigDecimal decimal1 = new BigDecimal(compareValue1);
        BigDecimal decimal2 = new BigDecimal(compareValue2);
        BigDecimal decimal3 = decimal1.multiply(decimal2);
        return decimal3.doubleValue();
	}
	
	/**
	 * Double两值相乘
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static BigDecimal multiplyDouble(BigDecimal value1, BigDecimal value2) {
		BigDecimal decimal1 = null != value1 ? value1 : BigDecimal.ZERO;
		BigDecimal decimal2 = null != value2 ? value2 : BigDecimal.ZERO;
		return decimal1.multiply(decimal2);
	}
	
	/**
	 * BigDecimal两值相加
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal addBigDecimal(BigDecimal value1, BigDecimal value2) {
		BigDecimal decimal1 = null != value1 ? value1 : BigDecimal.ZERO;
		BigDecimal decimal2 = null != value2 ? value2 : BigDecimal.ZERO;
        return decimal1.add(decimal2);
	}
	
	
	/**
	 * BigDecimal两值相减
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal subtractBigDecimal(BigDecimal value1, BigDecimal value2) {
		BigDecimal decimal1 = null != value1 ? value1 : BigDecimal.ZERO;
		BigDecimal decimal2 = null != value2 ? value2 : BigDecimal.ZERO;
        return decimal1.subtract(decimal2);
	}
	
	/**
	 * BigDecimal两值相除
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static double divideBigDecimal(BigDecimal value1, BigDecimal value2) {
		int scale = 2;
		BigDecimal bigDecimalDivide = value1.divide(value2, scale, BigDecimal.ROUND_HALF_UP); 
		return bigDecimalDivide.doubleValue(); 
	}

	
	/**
	 * 比较两个Double参数是否一致
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static boolean isEqualDouble(Double paramValue1, Double paramValue2) {
		if(compareDouble(paramValue1, paramValue2) == 0) {
			return true;
		}
		return false;
	}
	
	/**
	 * 比较两个Double参数是否一致
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static boolean isEqualBigDecimal(BigDecimal paramValue1, BigDecimal paramValue2) {
		BigDecimal decimal1 = null != paramValue1 ? paramValue1 : BigDecimal.ZERO;
		BigDecimal decimal2 = null != paramValue2 ? paramValue2 : BigDecimal.ZERO;
		int isEqual = decimal1.compareTo(decimal2);
		if (isEqual == 0) {
			return true;
		}
		return false;
	}
	
	/**
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static boolean isMoreThanBigDecimal(BigDecimal paramValue1, BigDecimal paramValue2) {
		BigDecimal decimal1 = null != paramValue1 ? paramValue1 : BigDecimal.ZERO;
		BigDecimal decimal2 = null != paramValue2 ? paramValue2 : BigDecimal.ZERO;
		int isEqual = decimal1.compareTo(decimal2);
		if(isEqual >= 0) {
			return true;
		}
		return false;
	}
	
	/**
	 * @param paramValue1
	 * @return
	 */
	public static boolean isMoreThanZero(BigDecimal paramValue1) {
		if(null == paramValue1) {
			return false;
		}
		BigDecimal decimal1 = null != paramValue1 ? paramValue1 : BigDecimal.ZERO;
		int isEqual = decimal1.compareTo(BigDecimal.ZERO);
		if(isEqual >= 0) {
			return true;
		}
		return false;
	}
	
	/**
	 * @param paramValue1
	 * @return
	 */
	public static boolean isLessThanZero(BigDecimal paramValue1) {
		return !isMoreThanZero(paramValue1);
	}
	
	/**
	 * 生成4位随字符方法
	 * @return
	 */
	public static String generateWord() {  
        String[] beforeShuffle = new String[] { "2", "3", "4", "5", "6", "7",  
                "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",  
                "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",  
                "W", "X", "Y", "Z" };  
        List<String> list = Arrays.asList(beforeShuffle);  
        Collections.shuffle(list);  
        StringBuilder sb = new StringBuilder();  
        for (int i = 0; i < list.size(); i++) {  
            sb.append(list.get(i));  
        }  
        String afterShuffle = sb.toString();  
        String result = afterShuffle.substring(5, 9);  
        return result;  
    } 
	
	public static String formatDifference(Double arg1,Double arg2){
		 NumberFormat format = NumberFormat.getPercentInstance();// 获取格式化类实例 
	     format.setMinimumFractionDigits(2);// 设置小数位 \
	     return format.format(arg1 / arg2);
	}
	
	private static boolean isMatch(String regex, String orginal){  
        if (orginal == null || orginal.trim().equals("")) {  
            return false;  
        }  
        Pattern pattern = Pattern.compile(regex);  
        Matcher isNum = pattern.matcher(orginal);  
        return isNum.matches();  
    }
	
	/**
	 * 校验是否是数字或者保留指定位数的小数
	 */
	public static boolean isPositiveDecimal(String orginal, int digit){
		BigDecimal bigDecimal = new BigDecimal(orginal);
		String param = DecimalFormat.getInstance().format(bigDecimal).replaceAll(",", "");  
        return isMatch("^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,"+digit+"})?$", param);  
    }
	
	/**
	 * 判断字符串是否为数字组成
	 * @param str
	 * @return
	 */
	public static boolean isNumeric(String str) { 
	     Pattern pattern = Pattern.compile("[0-9]*"); 
	     return pattern.matcher(str).matches();    
	} 
	
	/**
	 * 防止数字过长转换为科学计数法
	 * @param number
	 * @return
	 */
	public static String toPlainString(double number) {
		BigDecimal bigDecimal = BigDecimal.valueOf(number);
		return bigDecimal.toPlainString();
	}
	
    
    /**
     * 获取随机码方法(6位)
     * @return
     */
    public static String getRandomNum() {
    	int captcha = (int) (Math.random() * 900000 + 100000);
    	return String.valueOf(captcha);
    }
    
    /**
     * 获取随机码方法(4位)
     * @return
     */
    public static String getRandom4Num() {
    	int captcha = (int) (Math.random() * 9000 + 1000);
    	return String.valueOf(captcha);
    }
    
   public static Double divisionWithDouble(Double doubleValue, Double doubleValueTwo) {
	  if(doubleValue == null || doubleValueTwo == null || doubleValueTwo.equals(NumberUtils.DOUBLE_ZERO)) {
		  return null;
	  }
		
	   BigDecimal decimal = new BigDecimal(doubleValue);
	   BigDecimal integerDecimal = new BigDecimal(doubleValueTwo) ;
	   return divideBigDecimal(decimal, integerDecimal);
   }
   
   /**
	 * Integer两值相加
	 * @param paramValue1
	 * @param paramValue2
	 * @return
	 */
	public static Integer addInteger(Integer paramValue1, Integer paramValue2) {
		Integer addValue1 = null != paramValue1 ? paramValue1 : NumberUtils.INTEGER_ZERO;
		Integer addValue2 = null != paramValue2 ? paramValue2 : NumberUtils.INTEGER_ZERO;
		
        return addValue1 + addValue2;
	}
  
	/**
	 * 保留两位小数 四舍五入
	 * 
	 * @param bigDecimal
	 * @return String
	 */
	public static String format2BigDecimal(BigDecimal bigDecimal) {
		//线程不安全，不使用实例变量 Decimal formats are generally not synchronized
		DecimalFormat df = new DecimalFormat("0.00");
		if (null == bigDecimal){
			bigDecimal =  BigDecimal.ZERO;
		}
		return df.format(bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP));
	}
	
	/**
	 * 保留两位小数 四舍五入
	 * 
	 * @param doubleNum
	 * @return String
	 */
	public static String format2Double(Double doubleNum) {
		//线程不安全，不使用实例变量 Decimal formats are generally not synchronized
		DecimalFormat df = new DecimalFormat("0.00");
		if (null == doubleNum){
			doubleNum =  NumberUtils.DOUBLE_ZERO;
		}
		return df.format(new BigDecimal(doubleNum).setScale(2, BigDecimal.ROUND_HALF_UP));
	}
	
	/**
	 * 保留两位小数 四舍五入
	 * 
	 * @param doubleString
	 * @return String
	 */
	public static String format2String(String doubleString) {
		//线程不安全，不使用实例变量 Decimal formats are generally not synchronized
		DecimalFormat df = new DecimalFormat("0.00");
		Double doubleNum = NumberUtils.DOUBLE_ZERO;
		if (StringUtils.isNotBlank(doubleString)){
			doubleNum =  Double.parseDouble(doubleString);
		}
		return df.format(new BigDecimal(doubleNum).setScale(2, BigDecimal.ROUND_HALF_UP));
	}
}
